"""ETF 数据工具封装."""

from __future__ import annotations

import json
import logging
from typing import Any, Dict, Optional

from pydantic import BaseModel, Field

from ..data import ETFHistoricalDataset, fetch_etf_history
from .symbol import normalize_symbol
from .state import GLOBAL_DATA_STORE

logger = logging.getLogger(__name__)


def _format_etf_data_text(output: "ETFDataOutput") -> str:
    """将 ETF 数据工具输出格式化为易读的中文文本，便于理解."""
    lines = []
    
    # 标题
    etf_name = output.metadata.get("name") or "未知"
    lines.append(f"【{etf_name} ({output.symbol}) ETF 数据获取结果】")
    lines.append("")
    
    # 基本信息
    lines.append("📊 基本信息：")
    lines.append(f"  • ETF 代码: {output.symbol}")
    if output.normalized_symbol != output.symbol:
        lines.append(f"  • 标准化代码: {output.normalized_symbol}")
    if output.requested_limit is not None:
        lines.append(f"  • 数据条数: {output.actual_count} 条（请求 {output.requested_limit} 条）")
    else:
        lines.append(f"  • 数据条数: {output.actual_count} 条（全量数据）")
    lines.append(f"  • 数据范围: {output.start_date} 至 {output.end_date}")
    
    # 数据不足提示
    if output.insufficient:
        lines.append(f"  ⚠️  数据不足: {output.insufficient_reason or '历史数据不足'}")
    lines.append("")
    
    # 元数据信息
    lines.append("ℹ️  ETF 元数据：")
    metadata = output.metadata
    if metadata.get("name"):
        lines.append(f"  • 基金名称: {metadata['name']}")
    if metadata.get("exchange"):
        lines.append(f"  • 交易所: {metadata['exchange']}")
    if metadata.get("category"):
        lines.append(f"  • 基金类别: {metadata['category']}")
    if metadata.get("fund_family"):
        lines.append(f"  • 基金家族: {metadata['fund_family']}")
    if metadata.get("currency"):
        lines.append(f"  • 货币单位: {metadata['currency']}")
    if metadata.get("total_assets") is not None:
        # 格式化总资产，如果是大数字则使用科学计数法或添加单位
        total_assets = metadata["total_assets"]
        if total_assets >= 1e9:
            lines.append(f"  • 总资产: {total_assets/1e9:.2f} 十亿 {metadata.get('currency', '')}")
        elif total_assets >= 1e6:
            lines.append(f"  • 总资产: {total_assets/1e6:.2f} 百万 {metadata.get('currency', '')}")
        else:
            lines.append(f"  • 总资产: {total_assets:,.0f} {metadata.get('currency', '')}")
    if metadata.get("shares_outstanding") is not None:
        shares = metadata["shares_outstanding"]
        if shares >= 1e9:
            lines.append(f"  • 流通股数: {shares/1e9:.2f} 十亿股")
        elif shares >= 1e6:
            lines.append(f"  • 流通股数: {shares/1e6:.2f} 百万股")
        else:
            lines.append(f"  • 流通股数: {shares:,.0f} 股")
    if metadata.get("nav_price") is not None:
        lines.append(f"  • 净值价格: {metadata['nav_price']:.4f} {metadata.get('currency', '')}")
    if metadata.get("previous_close") is not None:
        lines.append(f"  • 前一交易日收盘价: {metadata['previous_close']:.4f} {metadata.get('currency', '')}")
    if metadata.get("source"):
        lines.append(f"  • 数据来源: {metadata['source']}")
    lines.append("")
    
    # 数据列信息
    lines.append("📈 历史数据字段：")
    # 将列名映射为中文说明（支持 AkShare 中文列名和英文列名）
    column_descriptions = {
        # AkShare 中文列名
        "开盘": "开盘价",
        "最高": "最高价",
        "最低": "最低价",
        "收盘": "收盘价",
        "成交量": "成交量",
        "成交额": "成交额",
        "振幅": "振幅",
        "涨跌幅": "涨跌幅",
        "涨跌额": "涨跌额",
        "换手率": "换手率",
        # 英文列名（兼容）
        "Open": "开盘价",
        "High": "最高价",
        "Low": "最低价",
        "Close": "收盘价",
        "Volume": "成交量",
        "Adj Close": "复权收盘价",
        "Dividends": "股息",
        "Stock Splits": "拆股",
    }
    column_list = []
    for col in output.columns:
        desc = column_descriptions.get(col, col)
        column_list.append(f"{col}（{desc}）")
    lines.append(f"  • 包含字段: {', '.join(column_list)}")
    lines.append("")
    
    # 使用提示
    lines.append("💡 提示：")
    lines.append(f"  • 数据已缓存，后续分析工具可使用标准化代码 '{output.normalized_symbol}' 访问")
    lines.append("  • 可以使用 quant_analysis_tool 进行量化分析")
    
    return "\n".join(lines)


class ETFDataInput(BaseModel):
    """ETF 数据工具的输入模型."""

    symbol: str = Field(
        ...,
        description=(
            "ETF 基金代码或交易符号。"
            "支持多种格式：中国 A 股 ETF（如 159919、512880）、"
            "美股 ETF（如 SPY、QQQ、TLT）、港股 ETF（如 2800.HK）等。"
            "工具会自动标准化符号格式。"
        ),
    )
    limit: Optional[int] = Field(
        default=None,
        description=(
            "最大返回历史数据条数。"
            "默认为 None，表示获取全量历史数据。"
            "如果指定 limit，则只返回最近 limit 条数据。"
        ),
    )


class ETFDataOutput(BaseModel):
    """工具输出模型，包含 ETF 历史数据和元信息."""

    symbol: str = Field(
        ...,
        description="原始输入的 ETF 代码或交易符号（未标准化）。",
    )
    normalized_symbol: str = Field(
        ...,
        description="标准化后的 ETF 代码，用于缓存和后续分析。",
    )
    requested_limit: Optional[int] = Field(
        ...,
        description="用户请求的最大历史数据条数。",
    )
    actual_count: int = Field(
        ...,
        description="实际返回的历史数据条数，可能小于 requested_limit。",
    )
    start_date: str = Field(
        ...,
        description="历史数据的起始日期，ISO 格式（YYYY-MM-DD）。",
    )
    end_date: str = Field(
        ...,
        description="历史数据的结束日期，ISO 格式（YYYY-MM-DD）。",
    )
    insufficient: bool = Field(
        ...,
        description="标识历史数据是否不足（当 requested_limit 不为 None 时，actual_count < requested_limit）。",
    )
    insufficient_reason: str | None = Field(
        default=None,
        description=(
            "当 insufficient 为 True 时，说明数据不足的原因。"
            "常见原因：新基金历史数据不足、数据源限制等。"
        ),
    )
    columns: list[str] = Field(
        ...,
        description=(
            "历史数据 DataFrame 的列名列表。"
            "通常包含：开盘、最高、最低、收盘、成交量等字段（AkShare 格式），"
            "或 Open、High、Low、Close、Volume 等字段（英文格式）。"
        ),
    )
    metadata: Dict[str, Any] = Field(
        ...,
        description=(
            "ETF 元数据字典，包含基金的基础信息。"
            "字段包括：name（名称）、exchange（交易所）、fund_family（基金家族）、"
            "category（类别）、currency（货币）、total_assets（总资产）、"
            "shares_outstanding（流通股数）、nav_price（净值价格）、"
            "previous_close（前一交易日收盘价）、source（数据来源）等。"
            "部分字段可能为 None（数据源未提供）。"
        ),
    )


# 向后兼容的别名
ETFDataToolInput = ETFDataInput
ETFDataToolOutput = ETFDataOutput


class ETFData:
    """ETF 数据获取工具，用于获取 ETF 历史 K 线与基础信息.
    
    这是一个普通的工具类，不依赖 LangChain 框架，可以直接使用。
    调用成功后会缓存数据以供其他分析工具使用。
    """

    def __init__(self) -> None:
        """初始化 ETF 数据工具."""
        pass

    def _serialize_dataset(self, dataset: ETFHistoricalDataset, requested_limit: Optional[int]) -> ETFDataOutput:
        """将历史行情数据集转换为结构化输出."""
        # 如果 requested_limit 为 None，表示获取全量数据，不检查是否不足
        if requested_limit is None:
            insufficient = False
            reason = None
        else:
            insufficient = dataset.count < requested_limit
            reason = (
                "历史数据不足，可能为新基金或数据源限制"
                if insufficient
                else None
            )

        metadata = dataset.metadata
        meta_payload = {
            "symbol": metadata.symbol if metadata else dataset.symbol,
            "name": metadata.name if metadata else None,
            "exchange": metadata.exchange if metadata else None,
            "fund_family": metadata.fund_family if metadata else None,
            "category": metadata.category if metadata else None,
            "currency": metadata.currency if metadata else None,
            "total_assets": metadata.total_assets if metadata else None,
            "shares_outstanding": metadata.shares_outstanding if metadata else None,
            "nav_price": metadata.nav_price if metadata else None,
            "previous_close": metadata.previous_close if metadata else None,
            "source": metadata.source if metadata else dataset.source,
        }

        return ETFDataOutput(
            symbol=dataset.symbol,
            normalized_symbol=dataset.symbol,
            requested_limit=requested_limit,
            actual_count=dataset.count,
            start_date=dataset.start.date().isoformat(),
            end_date=dataset.end.date().isoformat(),
            insufficient=insufficient,
            insufficient_reason=reason,
            columns=list(dataset.frame.columns),
            metadata=meta_payload,
        )

    def _normalize_cache_key(self, key: str) -> str | None:
        """将输入符号转换为标准缓存键."""
        trimmed = key.strip()
        if not trimmed:
            return None
        try:
            normalized = normalize_symbol(trimmed)
        except ValueError:
            normalized = trimmed.upper()
        return normalized

    def get_cached_dataset(self, key: str) -> ETFHistoricalDataset | None:
        """统一处理缓存读取."""
        cache_key = self._normalize_cache_key(key)
        if not cache_key:
            return None
        return GLOBAL_DATA_STORE.get_dataset(cache_key)

    def set_cached_dataset(self, key: str, dataset: ETFHistoricalDataset) -> None:
        """统一处理缓存写入."""
        cache_key = self._normalize_cache_key(key)
        if not cache_key:
            return
        GLOBAL_DATA_STORE.set_dataset(cache_key, dataset)

    def get_data(self, symbol: str, limit: Optional[int] = None) -> ETFDataOutput:
        """获取 ETF 数据并返回输出对象.

        Args:
            symbol: ETF 基金代码或交易符号
            limit: 最大返回历史数据条数，None 表示获取全量数据

        Returns:
            ETFDataOutput 对象，包含历史数据和元信息
        """
        cached_dataset = self.get_cached_dataset(symbol)
        if cached_dataset is not None:
            logger.info("etf_data 使用缓存：symbol=%s", cached_dataset.symbol)
            return self._serialize_dataset(cached_dataset, limit)

        logger.info("etf_data 正在获取 ETF 数据：symbol=%s, limit=%s", symbol, limit)
        dataset = fetch_etf_history(symbol, limit=limit)

        self.set_cached_dataset(dataset.symbol, dataset)
        self.set_cached_dataset(symbol, dataset)

        output = self._serialize_dataset(dataset, limit)
        logger.info(
            "etf_data 获取完成：symbol=%s, count=%s, start=%s, end=%s",
            dataset.symbol,
            dataset.count,
            dataset.start.date(),
            dataset.end.date(),
        )
        return output

    def get_data_json(self, symbol: str, limit: Optional[int] = None) -> str:
        """获取 ETF 数据并返回 JSON 格式的字符串.

        Args:
            symbol: ETF 基金代码或交易符号
            limit: 最大返回历史数据条数，None 表示获取全量数据

        Returns:
            JSON 格式的字符串
        """
        output = self.get_data(symbol, limit)
        return json.dumps(output.model_dump(), ensure_ascii=False)

    def get_data_text(self, symbol: str, limit: Optional[int] = None) -> str:
        """获取 ETF 数据并返回格式化的文本.

        Args:
            symbol: ETF 基金代码或交易符号
            limit: 最大返回历史数据条数，None 表示获取全量数据

        Returns:
            格式化的中文文本
        """
        output = self.get_data(symbol, limit)
        return _format_etf_data_text(output)

    def run(self, symbol: str | Dict[str, Any], limit: Optional[int] = None) -> str:
        """执行获取 ETF 数据并返回 JSON 格式的字符串（向后兼容方法）.

        此方法支持两种调用方式：
        1. `run(symbol="159919", limit=100)` - 直接传递参数
        2. `run({"symbol": "159919", "limit": 100})` - 传递字典（LangChain 兼容）

        Args:
            symbol: ETF 基金代码或包含 symbol 和 limit 的字典
            limit: 最大返回历史数据条数（当 symbol 是字符串时使用）

        Returns:
            JSON 格式的字符串
        """
        # 支持字典参数（向后兼容 LangChain 调用方式）
        if isinstance(symbol, dict):
            symbol_str = symbol.get("symbol", "")
            limit_val = symbol.get("limit", None)
        else:
            symbol_str = symbol
            limit_val = limit

        return self.get_data_json(symbol_str, limit_val)

    # 向后兼容的方法别名
    def _get_output(self, symbol: str, limit: Optional[int] = None) -> ETFDataOutput:
        """内部方法：获取原始输出对象（用于测试和调试）。"""
        return self.get_data(symbol, limit)


# 向后兼容的类别名
ETFDataTool = ETFData

